#pragma once

#include <string>
#include "nlohmann/json.hpp"
#include "api/p2pms_common.hpp"

namespace p2pms
{

// 通用消息结构
struct Message
{
	std::string cmd;
	std::string rid;      // 即 request id
	nlohmann::json data;  // 请求时为任意内容，响应时为 ResMsgData
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Message, cmd, rid, data)

// 通用响应数据结构
struct ResMsgData
{
	int code = 0;
	std::string msg;
	nlohmann::json data; // 可存任意结构
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ResMsgData, code, msg, data)

struct ResMessage
{
	std::string cmd;
	std::string rid;
	ResMsgData data;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ResMessage, cmd, rid, data)

////////////////////////////////////////////////////////////////////////////////////////////////////
// General protocols

#define LOGIN_REQ        "loginReq"
#define LOGIN_RES        "loginRes"
#define LOGIN_NOTIFY     "loginNotify"
#define LOGIN_ACK        "loginAck"
#define LOGOUT_REQ       "logoutReq"
#define LOGOUT_RES       "logoutRes"
#define LOGOUT_NOTIFY    "logoutNotify"
#define LOGOUT_ACK       "logoutAck"

// 登录请求数据
struct LoginReqData
{
	std::string user_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LoginReqData, user_id)

// 登录响应数据
struct LoginResData
{
	std::string user_id; // 登录的用户ID
	std::vector<std::string> users;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LoginResData, users)

struct LoginNotifyData
{
	std::string user_id; // 登录的用户ID
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LoginNotifyData, user_id)

struct LoginAckData
{
	std::string user_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LoginAckData, user_id)

// 登出请求数据
struct LogoutReqData
{
	std::string user_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LogoutReqData, user_id)

// 登出响应数据
struct LogoutResData
{
	std::string user_id; // 登出的用户ID
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LogoutResData, user_id)

// 登出通知数据
struct LogoutNotifyData
{
	std::string user_id; // 登出的用户ID
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(LogoutNotifyData, user_id)

////////////////////////////////////////////////////////////////////////////////////////////////////
// Call protocols

#define CALL_MAKE_REQ    "callMakeReq"
#define CALL_MAKE_RES    "callMakeRes"
#define CALL_MAKE_NOTIFY "callMakeNotify"
#define CALL_MAKE_ACK    "callMakeAck"
#define CALL_END_REQ     "callEndReq"
#define CALL_END_RES     "callEndRes"
#define CALL_END_NOTIFY  "callEndNotify"
#define CALL_END_ACK     "callEndAck"

struct CallMakeReqData
{
	std::string call_type; // "p2p" | "p2sp"
	std::string caller_id; // 呼叫者的用户ID
	std::string callee_id; // 被呼叫者的用户ID或房间ID
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CallMakeReqData, call_type, caller_id, callee_id)

struct CallMakeResData
{
	std::string call_type; // "p2p" | "p2sp"
	std::string call_id;   // 呼叫ID
	std::string caller_id; // 呼叫者的用户ID
	std::string callee_id; // 被呼叫者的用户ID或房间ID
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CallMakeResData, call_type, call_id, caller_id, callee_id)

struct CallMakeNotifyData
{
	std::string call_type; // "p2p" | "p2sp"
	std::string call_id;
	std::string caller_id; // user_id
	std::string callee_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CallMakeNotifyData, call_type, call_id, caller_id, callee_id)

struct CallMakeAckData
{
	std::string call_type; // "p2p" | "p2sp"
	std::string call_id;
	std::string caller_id; // user_id
	std::string callee_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CallMakeAckData, call_type, call_id, caller_id, callee_id)

struct CallEndReqData
{
	std::string call_id; // Call ID for which this end request is sent
	std::string user_id; // User ID of the person ending the call
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CallEndReqData, call_id, user_id)

struct CallEndResData
{
	std::string call_id; 
	std::string user_id; // User ID of the person ending the call
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CallEndResData, call_id, user_id)

struct CallEndNotifyData
{
	std::string call_id; // Call ID for which this end notification is sent
	std::string user_id; // Peer User ID of the person ending the call
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CallEndNotifyData, call_id, user_id)

struct CallEndAckData
{
	std::string call_id; // Call ID for which this end acknowledgment is sent
	std::string user_id; // Peer User ID of the person ending the call
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CallEndAckData, call_id, user_id)

////////////////////////////////////////////////////////////////////////////////////////////////////
// P2P protocols

#define P2P_CANDIDATE_NOTIFY     "p2pCandidateNotify"
#define P2P_NEGOTIATE_REQ        "p2pNegotiateReq"
#define P2P_NEGOTIATE_RES        "p2pNegotiateRes"
#define P2P_START_PUBLISH_REQ    "p2pStartPublishReq"
#define P2P_START_PUBLISH_RES    "p2pStartPublishRes"
#define P2P_START_PUBLISH_NOTIFY "p2pStartPublishNotify"
#define P2P_START_PUBLISH_ACK    "p2pStartPublishAck"
#define P2P_START_SUBSCRIBE_REQ  "p2pStartSubscribeReq"
#define P2P_START_SUBSCRIBE_RES  "p2pStartSubscribeRes"
#define P2P_START_PRODUCE_NOTIFY "p2pStartProduceNotify"
#define P2P_START_PRODUCE_ACK    "p2pStartProduceAck"
#define P2P_STOP_PUBLISH_REQ     "p2pStopPublishReq"
#define P2P_STOP_PUBLISH_RES     "p2pStopPublishRes"
#define P2P_STOP_PUBLISH_NOTIFY  "p2pStopPublishNotify"
#define P2P_STOP_PUBLISH_ACK     "p2pStopPublishAck"
#define P2P_STOP_SUBSCRIBE_REQ   "p2pStopSubscribeReq"
#define P2P_STOP_SUBSCRIBE_RES   "p2pStopSubscribeRes"
#define P2P_STOP_PRODUCE_NOTIFY  "p2pStopProduceNotify"
#define P2P_STOP_PRODUCE_ACK     "p2pStopProduceAck"

struct P2PCandidateNotifyData
{
	std::string call_id;   // Call ID for which this ICE candidate is related
	std::string user_id;   // User ID of the peer that sent this ICE candidate
	std::string sdp_mid;   // ICE candidate's mid
	int sdp_mline_index;   // ICE candidate's mline index
	std::string candidate; // ICE candidate SDP
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PCandidateNotifyData, call_id, user_id, sdp_mid, 
	sdp_mline_index, candidate)

struct P2PNegotiateReqData
{
	std::string call_id; // Call ID for which this negotiation is requested
	std::string user_id; // User ID of the person initiating the negotiation
	std::string sdp;     // SDP for the negotiation, used in P2P calls
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PNegotiateReqData, call_id, user_id, sdp)

struct P2PNegotiateResData
{
	std::string call_id; // Call ID for which this negotiation is responded
	std::string user_id; // User ID of the person responding to the negotiation
	std::string sdp;     // SDP for the negotiation, used in P2P calls
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PNegotiateResData, call_id, user_id, sdp)

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MediaInfo, 
	media_id, media_type, media_name, src_id, src_type, src_name)

struct P2PStartPublishReqData
{
	std::string call_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStartPublishReqData, call_id, user_id, media)

struct P2PStartPublishNotifyData
{
	std::string call_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStartPublishNotifyData, call_id, user_id, media)

struct P2PStartSubscribeReqData
{
	std::string call_id;
	std::string user_id;
	std::string pub_user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStartSubscribeReqData, call_id, user_id, pub_user_id, media)

struct P2PStartSubscribeResData
{
	std::string call_id;
	std::string user_id;
	std::string pub_user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStartSubscribeResData, call_id, user_id, pub_user_id, media)

struct P2PStopSubscribeReqData
{
	std::string call_id;
	std::string user_id;
	std::string pub_user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStopSubscribeReqData, call_id, user_id, media)

struct P2PStopSubscribeResData
{
	std::string call_id;
	std::string user_id;
	std::string pub_user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStopSubscribeResData, call_id, user_id, media)

struct P2PStartProduceNotifyData
{
	std::string call_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStartProduceNotifyData, call_id, media)

struct P2PStartProduceAckData
{
	std::string call_id;
	std::string user_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStartProduceAckData, call_id, user_id)

struct P2PStopPublishReqData
{
	std::string call_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStopPublishReqData, call_id, user_id, media)

struct P2PStopPublishResData
{
	std::string call_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStopPublishResData, call_id, user_id, media)

struct P2PStopPublishNotifyData
{
	std::string call_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStopPublishNotifyData, call_id, user_id, media)

struct P2PStopPublishAckData
{
	std::string call_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(P2PStopPublishAckData, call_id, user_id, media)

////////////////////////////////////////////////////////////////////////////////////////////////////
// SFU protocols

#define SFU_START_PUBLISH_REQ     "sfuStartPublishReq"
#define SFU_START_PUBLISH_RES     "sfuStartPublishRes"
#define SFU_START_PUBLISH_NOTIFY  "sfuStartPublishNotify"
#define SFU_START_PUBLISH_ACK     "sfuStartPublishAck"
#define SFU_START_SUBSCRIBE_REQ   "sfuStartSubscribeReq"
#define SFU_START_SUBSCRIBE_RES   "sfuStartSubscribeRes"
#define SFU_STOP_PUBLISH_REQ      "sfuStopPublishReq"
#define SFU_STOP_PUBLISH_RES      "sfuStopPublishRes"
#define SFU_STOP_PUBLISH_NOTIFY   "sfuStopPublishNotify"
#define SFU_STOP_PUBLISH_ACK      "sfuStopPublishAck"
#define SFU_STOP_SUBSCRIBE_REQ    "sfuStopSubscribeReq"
#define SFU_STOP_SUBSCRIBE_RES    "sfuStopSubscribeRes"
#define SFU_PREPARE_ROOM_REQ      "sfuPrepareRoomReq"
#define SFU_PREPARE_ROOM_RES      "sfuPrepareRoomRes"
#define SFU_JOIN_ROOM_REQ         "sfuJoinRoomReq"
#define SFU_JOIN_ROOM_RES         "sfuJoinRoomRes"
#define SFU_LEAVE_ROOM_REQ        "sfuLeaveRoomReq"
#define SFU_LEAVE_ROOM_RES        "sfuLeaveRoomRes"
#define SFU_CREATE_TRANSPORT_REQ  "sfuCreateTransportReq"
#define SFU_CREATE_TRANSPORT_RES  "sfuCreateTransportRes"
#define SFU_CONNECT_TRANSPORT_REQ "sfuConnectTransportReq"
#define SFU_CONNECT_TRANSPORT_RES "sfuConnectTransportRes"
#define SFU_START_PRODUCE_REQ     "sfuStartProduceReq"
#define SFU_START_PRODUCE_RES     "sfuStartProduceRes"
#define SFU_STOP_PRODUCE_REQ      "sfuStopProduceReq"
#define SFU_STOP_PRODUCE_RES      "sfuStopProduceRes"

struct SFUPrepareRoomReqData
{
	std::string user_id;
	std::string room_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUPrepareRoomReqData, user_id, room_id)

struct SFUPrepareRoomResData
{
	std::string room_id;
	std::string user_id;
	nlohmann::json rtp_caps; // router capabilities
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUPrepareRoomResData, room_id, user_id, rtp_caps)

struct SFUJoinRoomReqData
{
	std::string room_id;
	std::string user_id;
	nlohmann::json rtp_caps;
	nlohmann::json sctp_caps;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUJoinRoomReqData, room_id, user_id, rtp_caps, sctp_caps)

struct SFUJoinRoomResData
{
	std::string room_id;
	std::string user_id;
	std::vector<std::string> users;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUJoinRoomResData, room_id, user_id, users)

struct SFULeaveRoomReqData
{
	std::string room_id;
	std::string user_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFULeaveRoomReqData, room_id, user_id)

struct SFUCreateTransportReqData
{
	std::string room_id;
	std::string user_id;
	std::string transport_type;
	bool force_tcp;
	bool producing;
	bool consuming;
	nlohmann::json sctp_caps;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUCreateTransportReqData, room_id, user_id, transport_type,
	force_tcp, producing, consuming, sctp_caps)

struct SFUCreateTransportResData
{
	std::string room_id;
	std::string user_id;
	std::string transport_type;
	std::string transport_id;
	nlohmann::json ice_parameters;
	nlohmann::json ice_candidates;
	nlohmann::json dtls_parameters;
	nlohmann::json sctp_parameters;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUCreateTransportResData, room_id, user_id, transport_type,
	transport_id, ice_parameters, ice_candidates, dtls_parameters, sctp_parameters)

struct SFUConnectTransportReqData
{
	std::string room_id;
	std::string user_id;
	std::string transport_type;
	std::string transport_id;
	std::string send_or_recv;
	nlohmann::json dtls_parameters;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUConnectTransportReqData, room_id, user_id, transport_type, 
	transport_id, send_or_recv, dtls_parameters)

struct SFUConnectTransportResData
{
	std::string room_id;
	std::string user_id;
	std::string transport_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUConnectTransportResData, transport_id)

struct SFUStartProduceReqData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
	std::string transport_id;
	std::string kind;
	nlohmann::json rtp_parameters;
	nlohmann::json app_data;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartProduceReqData, room_id, user_id, media, transport_id,
	kind, rtp_parameters, app_data)

struct SFUStartProduceResData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
	std::string producer_id;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartProduceResData, room_id, user_id, media, producer_id)

struct SFUStartPublishReqData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartPublishReqData, room_id, user_id, media)

struct SFUStartPublishResData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartPublishResData, room_id, user_id, media)

struct SFUStartPublishNotifyData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartPublishNotifyData, room_id, user_id, media)

struct SFUStartPublishAckData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartPublishAckData, room_id, user_id)

struct SFUStartSubscribeReqData
{
	std::string room_id;
	std::string user_id;
	std::string pub_user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartSubscribeReqData, room_id, user_id, pub_user_id, media)

struct SFUStartSubscribeResData
{
	std::string room_id;
	std::string user_id;
	std::string pub_user_id;
	MediaInfo media;
	std::string producer_id; // ID of the producer being subscribed to
	std::string consumer_id; // ID of the consumer created for this subscription
	nlohmann::json rtp_parameters; // RTP parameters for the subscription
	nlohmann::json app_data; // Additional application data
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartSubscribeResData, room_id, user_id, pub_user_id, 
	media, producer_id, consumer_id, rtp_parameters, app_data)

struct SFUStartProduceNotifyData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartProduceNotifyData, room_id, user_id, media)

struct SFUStartProduceAckData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStartProduceAckData, room_id, user_id, media)

struct SFUStopPublishReqData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopPublishReqData, room_id, user_id, media)

struct SFUStopPublishResData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopPublishResData, room_id, user_id, media)

struct SFUStopPublishNotifyData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopPublishNotifyData, room_id, user_id, media)

struct SFUStopPublishAckData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopPublishAckData, room_id, user_id, media)

struct SFUStopSubscribeReqData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopSubscribeReqData, room_id, user_id, media)

struct SFUStopSubscribeResData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopSubscribeResData, room_id, user_id, media)

struct SFUStopProduceNotifyData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopProduceNotifyData, room_id, user_id, media)

struct SFUStopProduceAckData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopProduceAckData, room_id, user_id, media)

struct SFUStopProduceReqData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
	std::string producer_id; // ID of the producer to stop
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopProduceReqData, room_id, user_id, media, producer_id)

struct SFUStopProduceResData
{
	std::string room_id;
	std::string user_id;
	MediaInfo media;
	std::string producer_id; // ID of the producer that was stopped
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(SFUStopProduceResData, room_id, user_id, media, producer_id)

} // namespace p2pms